我認為要從0開始學習Pwn是一件很難的事情,就算想要做簡單的Stack buffer overflow return 到程式碼當中的 system("bin/sh"); 這件事,看似簡單,實際上是需要大量的Background knowledge來支撐的。
因此這次想要從最簡單的Reverse開始,一直到如何做簡單的Stack buffer overflow拿到Shell權限,會盡可能地介紹到Stack buffer overflow所需要的知識,從常用暫存器和組合語言一直到覆蓋掉Return address讓RIP跳到期望的Address。
這篇文章會有一些未提及的內容,例如更多的通用暫存器或EFLAGS等資訊,這裡的內容比較適合只有對基本組合語言有些了解的初學者,因此會更專注於這次實作相關的資訊,如果有興趣,可以進一步研究其他相關內容。
由於每個作業系統、編譯器或程式語言等等,都可能會讓底層的運作有所不同,這次的教學會以Ubuntu 20.04.1的GCC 9.4.0以及Windows 11 Professional使用Cygwin Terminal的GCC 12.4.0,兩種不同的環境來操作。
在Ubuntu環境下會使用GDB來做逆向,Windows環境底下會用IDA來做逆向,使用其他的工具也可以,只是在解讀時會有所差異。
在做逆向時會很常發現RAX、RBX、RCX、RDX等等的暫存器,有時又會看到其他文章寫EAX、EBX、ECX、EDX,這其實是與位元有關。
AX是16位元的暫存器,其中又分為AL和AH,AL是low的意思,AH是high的意思,而EAX則是32位元的暫存器,RAX是64位元的暫存器。
以下介紹常用的暫存器,也是在做逆向或基本Stack buffer overflow會用到的暫存器。
RAX:Accumulator Register,運算暫存器。
RBX:Base Register,基底暫存器,屬於Callee-saved,通常是一個不會改變的暫存器。
RCX:Counter Register,計數暫存器,通常會用在迴圈的計數。
RDX:Data Register,數據暫存器,通常在做大值運算時會與RAX一起使用。
RSP:Stack Pointer,指向Stack的頂端。
RBP:Base Pointer,指向Stack的底端。
RIP:Instruction Pointer,指向下一條需要執行的位址。
RSI:Source Index,來源字串的位址。
RDI:Destination Index,目的字串的位址。
除了以上這些,通用暫存器還有R8、R9 … R15。
這種要背的東西一次背完頭很痛,剩下的下次繼續說。